///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "WNFileIO/inc/WNWriteFileBuffer.h"
#include "WNMemory/inc/WNAllocation.h"
#include "WNContainers/inc/WNSerializer.h"

#include <stdarg.h>

using namespace WNFileIO;
using namespace WNMemory;

WNWriteTextFileBuffer::WNWriteTextFileBuffer(WNFileBufferType _type, WN_SIZE_T _buffSize):
    WNFileBuffer(_type),
    mBuffUsage(0),
    mBuffSize(_buffSize) {
    mCurrentBuff = static_cast<WN_CHAR*>(WNMalloc(_buffSize));
    WN_RELEASE_ASSERT(mCurrentBuff != WN_NULL);
}

WNWriteTextFileBuffer::~WNWriteTextFileBuffer() {
    if(mFile.IsValid()) {
        DumpToFile();
        if(mCurrentBuff != WN_NULL) {
            WNFree(mCurrentBuff);
        }
    }
}

WN_CHAR* WNWriteTextFileBuffer::ReserveBytes(WN_SIZE_T _numBytes, WN_SIZE_T& _returnedBytes) {   
    if(_numBytes + mBuffUsage > mBuffSize) {
        if(mBuffUsage > 0){
            if(!DumpToFile()){
                WNFree(mCurrentBuff);
                _returnedBytes = 0;
                return(WN_NULL);
            }
        }
        if(_numBytes > mBuffSize) {
            mCurrentBuff = static_cast<WN_CHAR*>(WNRealloc(mCurrentBuff, _numBytes));
            WN_RELEASE_ASSERT(mCurrentBuff != WN_NULL);
            mBuffUsage = 0;
            mBuffSize = _numBytes;
        }
    }
    
    _returnedBytes = _numBytes;
    
    return(mCurrentBuff + mBuffUsage);
}

WN_BOOL WNWriteTextFileBuffer::DumpToFile() {
    if(!mFile.IsValid() || mBuffUsage == 0) {
        return(WN_FALSE);
    }
    WN_SIZE_T written = mFile.WriteData(mCurrentBuff, mBuffUsage);
    if(written != mBuffUsage){
        return(WN_FALSE);
    }
    return(WN_TRUE);
}

WNContainers::WNDataBufferType WNWriteTextFileBuffer::GetType() {
    switch(mType){
    case WNFileBuffer::WNText:
        return(WNContainers::WriteText);
    case WNFileBuffer::WNBinary:
        return(WNContainers::WriteBinary);
    }
    return(WNContainers::WriteText);
}

WNFile::WNFileError WNWriteTextFileBuffer::SetFile(const WN_CHAR* fileName) {
    WN_RELEASE_ASSERT_DESC(!mFile.IsValid(), "Error, trying to set a file on a text buffer that already exists");
    return(mFile.OpenFile(fileName, WNFile::WN_CLOBBER | WNFile::WN_EXCLUSIVE | WNFile::WN_WRITE | WNFile::WN_CREATE | WNFile::WN_STREAM));
}

WN_BOOL WNWriteTextFileBuffer::Serialize(WN_UINT32 _flags, const WNContainers::WNSerializerBase& _serializer){
    mBuffUsage += _serializer.Serialize(*this, _flags);
    return(WN_TRUE);
}

